//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#include "rs/Assert.hpp"
#include "rs/ThreadLocalPtr.hpp"
#include <cstdarg>
#include <cstdio>

namespace rs
{
    namespace
    {
        struct ReportHandlerContainer
        {
            ReportHandlerContainer(Assert::ReportHandler handler)
            : handler_(handler) {
            }
            
            Boolean operator()(Char8 const* file, RsSize line, Char8 const* condition, Char8 const* message) {
                return handler_(file, line, condition, message);
            }
            
            Assert::ReportHandler handler_;
            
        private:
            ReportHandlerContainer(ReportHandlerContainer const& other);
            ReportHandlerContainer& operator=(ReportHandlerContainer const& other);
        };
        
        Boolean DefaultReportHandler(Char8 const* file, RsSize line, Char8 const* condition, Char8 const* message) {
            std::fprintf(stderr, "%s(%d): ASSERTION FAILURE:\n", file, line);
            
            if (condition != 0) {
                std::fprintf(stderr, "'%s'\n", condition);
            }
            
            if (message != 0) {
                std::fprintf(stderr, "%s\n", message);
            }
            
            std::fprintf(stderr, "\n");
            
            return true;
        }
        
        ThreadLocalPtr< ReportHandlerContainer > handler_;
        //Assert::ReportHandler handler_ = &DefaultReportHandler;
    }
    
    Boolean Assert::Report(Char8 const* file, RsSize line, Char8 const* condition, Char8 const* message) {
        ReportHandler handler = GetReportHandler();
        return (handler ? handler(file, line, condition, message) : DefaultReportHandler(file, line, condition, message));    }

    Boolean Assert::Reportf(Char8 const* file, RsSize line, Char8 const* condition, Char8 const* message, ...) {
        if (message != 0) {
            Char8 formattedMessageBuffer[1024];
            std::va_list arguments;
            va_start(arguments, message);
            std::vsnprintf(formattedMessageBuffer, sizeof(formattedMessageBuffer), message, arguments);
            va_end(arguments);
            return Report(file, line, condition, formattedMessageBuffer);
        }
        else {
            return Report(file, line, condition, 0);
        }
    }
    
    Assert::ReportHandler Assert::GetReportHandler() {
        if (handler_.Get() == 0) {
            handler_.Reset(new ReportHandlerContainer(&DefaultReportHandler));
        }
        
        return handler_.Get()->handler_;
        //return handler_;
    }
    
    void Assert::SetReportHandler(ReportHandler handler) {
        handler_.Reset(new ReportHandlerContainer(handler));
        //handler_ = handler;
    }
}